package com.ruoyi.asms.controller;

import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.ruoyi.ams.controller.AmsAssetTypeController;
import com.ruoyi.ams.controller.AmsOwnAddressController;
import com.ruoyi.asms.domain.*;
import com.ruoyi.asms.domain.bo.UnResovleFaultMsgBo;
import com.ruoyi.asms.domain.bo.UrgeWorkBo;
import com.ruoyi.asms.domain.dto.DispatchWorkDto;
import com.ruoyi.asms.domain.dto.WorkOrderDto;
import com.ruoyi.asms.domain.vo.*;
import com.ruoyi.asms.service.*;
import com.ruoyi.common.core.domain.AsmsAssetFullInfo;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.SysFile;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.AmsAssetType;
import com.ruoyi.common.core.domain.model.AmsOwnAddress;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.BusinessUtils;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.SecurityUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.security.annotation.PreAuthorize;
import com.ruoyi.security.service.TokensService;
import com.ruoyi.common.wx.config.WxMaConfiguration;
import com.ruoyi.common.wx.config.WxSubcribConfig;
import com.ruoyi.file.controller.SysFileController;
import com.ruoyi.system.controller.SysDeptController;
import com.ruoyi.system.controller.SysUserController;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * 故障信息Controller
 *
 * @author yfkj
 * @date 2021-10-21
 */
@RestController
@RequestMapping("/asms/AsmsFault")
public class AsmsFaultController extends BaseController {
    @Autowired
    private IAsmsFaultService faultService;
    @Autowired
    private IFaultInfoViewService faultInfoViewService;
    @Autowired
    private IAsmsFaultAssetService faultAssetService;
    @Autowired
    private IAsmsFaultReportStageService reportService;
    @Autowired
    private IAsmsFaultDispatchStageService dispatchService;
    @Autowired
    private IAsmsFaultConfirmStageService confirmService;
    @Autowired
    private IAsmsFaultFeedbackStageService asmsFaultFeedbackStageService;
    @Autowired
    private IAsmsFaultAssetReasonService asmsFaultAssetReasonService;
    @Autowired
    private IAsmsMaintenanceChargeInfoService asmsMaintenanceChargeInfoService;
    @Autowired
    private IAsmsMaintenanceAssetService asmsMaintenanceAssetService;
    @Autowired
    private IAsmsAssetFullInfoService asmsAssetFullInfoService;
    @Autowired
    private IAsmsFaultResolveStageService resovleService;
    @Autowired
    private IAsmsOwnChargeInfoService asmsOwnChargeInfoService;
    @Autowired
    private TokensService tokenService;
    @Autowired
    private AsyncService asyncService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private AsmsReusingService asmsReusingService;
    @Autowired
    private IAsmsOwnAddressAssetCodeService asmsOwnAddressAssetCodeService;
//    @Autowired
//    private RemoteUserService remoteUserService;
//    @Autowired
//    private RemoteAssetAddressService remoteAssetAddressService;
//    @Autowired
//    private RemoteDeptService remoteDeptService;
//    @Autowired
//    private RemoteFileService remoteFileService;
//    @Autowired
//    private RemoteAssetTypeService remoteAssetTypeService;
    @Autowired
    private SysUserController userController;
    @Autowired
    private SysDeptController deptController;
    @Autowired
    private SysFileController fileController;

    @Autowired
    private AmsAssetTypeController assetTypeController;
    @Autowired
    private AmsOwnAddressController amsOwnAddressController;
    /**
     * 查询故障信息列表
     */
    @PreAuthorize
    @GetMapping("/list")
    public TableDataInfo list(AsmsFault asmsFault) {
        QueryWrapper<AsmsFault> queryWrapper = new QueryWrapper<>();
        startPage();
        List<AsmsFault> list = faultService.list();
        return getDataTable(list);
    }

    @PostMapping("/reportIotFault")
    public AjaxResult reportIotFault(@RequestParam("assetId") Long assetId,
                                     @RequestParam("faultAssetReasonId") Long faultAssetReasonId) {
        AsmsAssetFullInfo assetFullInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                .eq(AsmsAssetFullInfo.ASSET_ID, assetId));

        ReportFaultVo reportFaultVo = new ReportFaultVo();
        reportFaultVo.setAddressId(assetFullInfo.getAddressId());
        List<ReportFaultAssetVo> vos = new ArrayList<>();
        ReportFaultAssetVo vo = new ReportFaultAssetVo();
        BeanUtils.copyProperties(assetFullInfo, vo);
        reportFaultVo.setUserId(1L);
        vos.add(vo);
        reportFaultVo.setFaultAssets(vos);
        return reportFault(reportFaultVo);
    }

    @PostMapping("/reportOldPlatFormFault")
    public AjaxResult reportOldPlatFormFault(@RequestBody OldPlatFormFaultVo faultInfo) {
        AsmsOwnAddressAssetCode codeInfo = asmsOwnAddressAssetCodeService
                .getOne(new QueryWrapper<AsmsOwnAddressAssetCode>()
                .eq(AsmsOwnAddressAssetCode.CODE, faultInfo.getAddressCode()), false);

        ReportFaultVo reportFaultVo = new ReportFaultVo();
        BeanUtils.copyProperties(faultInfo, reportFaultVo);
        reportFaultVo.setAddressId(codeInfo.getAddressId());
        reportFaultVo.setRemark(faultInfo.getFaultId());

        R<SysUser> rSysUser = userController.saveOrGetUser(faultInfo.getInstitutionName(),
                faultInfo.getPhonenumber(), faultInfo.getNickName(), faultInfo.getWxOpenId());

        reportFaultVo.setUserId(rSysUser.getData().getUserId());
        AsmsAssetFullInfo assetFullInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                .eq(AsmsAssetFullInfo.ASSET_CODE, faultInfo.getAssetCode()));

        ReportFaultAssetVo assetInfoVo = new ReportFaultAssetVo();
        BeanUtils.copyProperties(assetFullInfo, assetInfoVo);
        assetInfoVo.setDescription(faultInfo.getDescription());
        assetInfoVo.setDescriptionImages(faultInfo.getFaultImage());
        assetInfoVo.setIsFinish(1);
        reportFaultVo.setFaultAssets(Lists.newArrayList(assetInfoVo));

        return AjaxResult.success(doReportFault(rSysUser.getData(), reportFaultVo));
    }

    @ApiOperation(value = "故障报修")
    @PostMapping("/reportFault")
    public AjaxResult reportFault(@RequestBody ReportFaultVo reportFaultVo) {
        if (reportFaultVo.getFaultAssets() == null) {
            return error("请选择故障设备！");
        }
        SysUser user = new SysUser();
        user.setUserId(1L);
        user.setNickName("系统服务");
        user.setPhonenumber("8888888888");
        if (reportFaultVo.getUserId() != 1L) {
            user = tokenService.getLoginUser().getSysUser();
            BeanUtils.copyProperties(reportFaultVo, user);
            user.setUpdateTime(System.currentTimeMillis());
            //更新用户
            Long[] roleIds = new Long[1];
            if (user.getDeptId() == null || user.getDeptId() == 0L) {
                user.setDeptId(reportFaultVo.getFaultAssets().get(0).getOwnDeptId());
                roleIds[0] = 4L;
                user.setRoleIds(roleIds);
                R r = userController.updateUserAndRole(user);
                if (r.getCode() == R.FAIL) {
                    return error(r.getMsg());
                }
            } else {
                //user.setRoleIds(roleIds);
                R r = userController.updateUserAndRole(user);
                if (r.getCode() == R.FAIL) {
                    return error(r.getMsg());
                }
            }
        }
        String resultMsg = doReportFault(user, reportFaultVo);

        AjaxResult result = AjaxResult.success(resultMsg);
        //result.put("tmplIds", Lists.newArrayList(WxSubcribConfig.DISPATCH_NOTICE_TO_USER, WxSubcribConfig.FAULT_RESOLVE_NOTICE));
        return result;
    }

    @Transactional
    public String doReportFault(SysUser user, ReportFaultVo reportFaultVo) {
        //故障基础信息
        AsmsFault asmsFault = new AsmsFault();
        BeanUtils.copyProperties(reportFaultVo, asmsFault);
        asmsFault.setFaultFindUserId(user.getUserId());
        asmsFault.setCreateBy(user.getUserName());
        asmsFault.setCreateTime(System.currentTimeMillis());
        if (StringUtils.isEmpty(reportFaultVo.getRemark())) {
            asmsFault.setRemark("无码报修");
        }
        faultService.save(asmsFault);
        String resultMsg = "";

        for (ReportFaultAssetVo reportFaultAssetVo : reportFaultVo.getFaultAssets()) {
            AsmsAssetFullInfo assetFullInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                    .select(AsmsAssetFullInfo.MAINTENANCE_DEPT_ID, AsmsAssetFullInfo.M_ANCESTORS, AsmsAssetFullInfo.OWN_DEPT_ID)
                    .eq(AsmsAssetFullInfo.ASSET_ID, reportFaultAssetVo.getAssetId()), false);

            //故障资产设备信息
            AsmsFaultAsset faultAsset = new AsmsFaultAsset();
            BeanUtils.copyProperties(reportFaultAssetVo, faultAsset);
            faultAsset.setFaultId(asmsFault.getFaultId());
            faultAsset.setRemark(asmsFault.getRemark());
            faultAsset.setCreateBy(user.getUserName());
            faultAsset.setCreateTime(System.currentTimeMillis());
            faultAsset.setMaintenanceDeptId(assetFullInfo.getMaintenanceDeptId());
            faultAsset.setMaintenanceDeptAncestors(assetFullInfo.getMAncestors());
            faultAsset.setOwnDeptId(assetFullInfo.getOwnDeptId());
            //faultAsset.setOwnDeptAncestors(assetFullInfo.getUAncestors());

            List<String> faultImages = reportFaultVo.getFaultImages();
            String descriptionImages = null;
            if (faultImages != null) {
                StringBuilder builder = new StringBuilder();
                int flag = 0;
                for (String faultImage : faultImages) {
                    flag ++;
                    builder.append(faultImage);
                    if (faultImages.size() != flag)
                        builder.append(",");
                }
                descriptionImages = builder.toString();
            }
            faultAsset.setDescriptionImages(descriptionImages);
            faultAssetService.save(faultAsset);
            //报修初始阶段
            AsmsFaultReportStage reportStage = new AsmsFaultReportStage();
            reportStage.setFaultAssetId(faultAsset.getFaultAssetId());
            reportStage.setStartTime(System.currentTimeMillis());
            reportStage.setUrgencyDegree(reportFaultVo.getUrgencyDegree());
            R<List<SysUser>> oDeptCharger = userController.getOwnDeptCharger(reportFaultAssetVo.getOwnDeptId());
            reportStage.setOwnChargeUserId(oDeptCharger.getData().get(0).getUserId());
            reportStage.setOwnChargeDeptId(reportFaultAssetVo.getOwnDeptId());
            boolean needAgreen = false;
            boolean sendReport = false;
            String msg = "";
            if (needAgreen) {
                //需要负责人审核
                reportStage.setStatus(0);
                //将故障报修阶段信息设为故障初始报修审核阶段
                faultAsset.setStage(1);
                faultAssetService.updateById(faultAsset);
                msg = "请等待负责人同意！";

            } else {
                if (faultAsset.getIsFinish() != null && faultAsset.getIsFinish() == 0) {
                    //用户自行解决
                    reportStage.setStatus(2);
                } else {
                    //同意报修
                    reportStage.setStatus(1);
                    //将故障报修阶段信息设为故障派单阶段
                    sendReport = true;
                    msg = "请等待维修！";
                }
                //报修初始阶段结束
                reportStage.setEndTime(System.currentTimeMillis());
            }
            reportService.save(reportStage);
            if (reportFaultVo.getFaultAssets().size() > 1) {
                resultMsg = resultMsg + reportFaultAssetVo.getAssetTypeName() + "故障报修成功！" + msg + "<br/>";
            } else {
                resultMsg = resultMsg + "故障报修成功！" + msg;
            }
            if (!sendReport) {
                continue;
            }
            //派单阶段
            AsmsFaultDispatchStage dispatchStage = new AsmsFaultDispatchStage();
            dispatchStage.setFaultAssetId(faultAsset.getFaultAssetId());
            dispatchStage.setStartTime(System.currentTimeMillis());
            dispatchStage.setStatus(0);
            dispatchStage.setMaintenanceDeptId(assetFullInfo.getMaintenanceDeptId());
            dispatchService.save(dispatchStage);
            faultAsset.setStage(2);
            faultAssetService.updateById(faultAsset);
            //消息发送!
            //asyncService.sendReportFaultWxSubscribeMsg(asmsFault, faultAsset, user);
            //自动派单
            DispatchVo dispatchVo = new DispatchVo();
            dispatchVo.setFinder(user);
            dispatchVo.setAssetTypeName(reportFaultAssetVo.getAssetTypeName());
            dispatchVo.setFaultAddress(reportFaultVo.getAddressFullInfo());
            dispatchVo.setFaultAssetId(faultAsset.getFaultAssetId());
            dispatchVo.setFaultDescription(faultAsset.getDescription());
            AsmsMaintenanceChargeInfo chargeInfo = new AsmsMaintenanceChargeInfo();
            chargeInfo.setChargeAssetTypes(reportFaultAssetVo.getAssetTypeId() + "");
            chargeInfo.setMaintenanceChargeAddressIds(reportFaultVo.getAddressId() + "");
            chargeInfo.setMaintenanceChargeDeptIds(reportFaultAssetVo.getOwnDeptId() + "");
            chargeInfo.setMaintenanceDeptId(assetFullInfo.getMaintenanceDeptId());
            asyncService.autoDispatch(dispatchVo, chargeInfo);
        }
        return resultMsg;
    }

    @ApiOperation(value = "管理员查看故障记录", response = FaultBasicInfoVo.class)
    @GetMapping("/getFaultDisPatchList")
    public AjaxResult getFaultList(@ApiParam(value = "0未派单 1已派单 2已维修 3已完成", required = true) Integer status) {
        List<FaultBasicInfoVo> vos = new ArrayList<>();
        QueryWrapper<FaultInfoView> wrapper = new QueryWrapper<>();

        //用户所能见的部门都能看对应部门的故障列表
        Set<Long> deptIds = tokenService.getLoginUser().getDeptIds();
        if (Objects.isNull(deptIds) || deptIds.size() == 0) {
            return AjaxResult.success(vos);
        }
        List<AsmsFaultDispatchStage> stageList = dispatchService.list(new QueryWrapper<AsmsFaultDispatchStage>()
                .select(AsmsFaultDispatchStage.FAULT_ASSET_ID).in(AsmsFaultDispatchStage.MAINTENANCE_DEPT_ID, deptIds)
        );
        Set<Long> faultAssetIds = stageList.stream().map(AsmsFaultDispatchStage::getFaultAssetId).collect(Collectors.toSet());
        if (faultAssetIds.size() == 0) {
            return AjaxResult.success(vos);
        }

        //不看已撤销的故障
        Set<Long> hasCancelFaults = asmsReusingService.getHasCancelFaults();
        if (hasCancelFaults.size() > 0) {
            wrapper.notIn(FaultInfoView.FAULT_ASSET_ID, hasCancelFaults);
        }
        switch (status) {
            case 0:
                //管理员查看未派单的故障
                wrapper.eq(FaultInfoView.STAGE, 2);
                break;
            case 1:
                //管理员查看已派单的故障
                wrapper.eq(FaultInfoView.STAGE, 3);
                break;
            case 2:
                //管理员查看已维修的故障
                wrapper.eq(FaultInfoView.STAGE, 4).eq(FaultInfoView.IS_FINISH, 1);
                break;
            case 3:
                //管理员查看已完成的故障
                wrapper.eq(FaultInfoView.IS_FINISH, 0);
                break;
        }

        //按条件查询故障资产数据
        wrapper.in(FaultInfoView.FAULT_ASSET_ID, faultAssetIds);
        List<FaultInfoView> faultInfoViews = faultInfoViewService.list(wrapper);
        if (faultInfoViews.size() == 0) {
            return AjaxResult.success(vos);
        }

        //构造集合用于查询相应的数据
        Set<Long> finderIds = faultInfoViews.stream().map(FaultInfoView::getFaultFindUserId).collect(Collectors.toSet());
        Set<Long> addressIds = faultInfoViews.stream().map(FaultInfoView::getAddressId).collect(Collectors.toSet());
        Set<Long> mainUserIds = faultInfoViews.stream().filter(o -> o.getFaultResolveUserId() != null).map(FaultInfoView::getFaultResolveUserId).collect(Collectors.toSet());
        Set<Long> assetIds = faultInfoViews.stream().map(FaultInfoView::getAssetId).collect(Collectors.toSet());
        Set<Long> faultAssetIdSet = faultInfoViews.stream().map(FaultInfoView::getFaultAssetId).collect(Collectors.toSet());

        //并行执行、Map查询节约时间
        CompletableFuture<R<Map<Long, SysUser>>> f1 = CompletableFuture.supplyAsync(() ->
                userController.getUserListByIds(finderIds.toArray(new Long[0]))
        );
        CompletableFuture<R<Map<Long, AmsOwnAddress>>> f2 = CompletableFuture.supplyAsync(() ->
                amsOwnAddressController.getAddressByIds(addressIds.toArray(new Long[0]))
        );
        CompletableFuture<R<Map<Long, SysUser>>> f3 = CompletableFuture.supplyAsync(() ->
                userController.getUserListByIds(mainUserIds.toArray(new Long[0]))
        );
        CompletableFuture<List<AsmsAssetFullInfo>> f4 = CompletableFuture.supplyAsync(() ->
                asmsAssetFullInfoService.list(new QueryWrapper<AsmsAssetFullInfo>()
                        .select(AsmsAssetFullInfo.ASSET_ID, AsmsAssetFullInfo.ASSET_TYPE_NAME)
                        .in(AsmsAssetFullInfo.ASSET_ID, assetIds))
        );
        CompletableFuture<List<AsmsFaultReportStage>> f5 = CompletableFuture.supplyAsync(() ->
                reportService.list(new QueryWrapper<AsmsFaultReportStage>()
                        .select(AsmsFaultReportStage.FAULT_ASSET_ID, AsmsFaultReportStage.URGENCY_DEGREE)
                        .in(AsmsFaultReportStage.FAULT_ASSET_ID, faultAssetIdSet))
        );
        CompletableFuture<List<AsmsFaultDispatchStage>> f6 = CompletableFuture.supplyAsync(() ->
                dispatchService.list(new QueryWrapper<AsmsFaultDispatchStage>()
                        .select(AsmsFaultDispatchStage.FAULT_ASSET_ID, AsmsFaultDispatchStage.IS_ACTIVE_RECEIVE)
                        .in(AsmsFaultDispatchStage.FAULT_ASSET_ID, faultAssetIdSet))
        );
        CompletableFuture<List<AsmsFaultResolveStage>> f7 = CompletableFuture.supplyAsync(() ->
                resovleService.list(new QueryWrapper<AsmsFaultResolveStage>()
                        .select(AsmsFaultResolveStage.IS_DELAY_RESOLVE, AsmsFaultResolveStage.DELAY_DAY_NUM, AsmsFaultResolveStage.DELAY_REASON)
                        .ne(AsmsFaultResolveStage.STATUS, -2)
                        .in(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetIdSet))
        );

        try {
            //校验RPC调用是否成功
            BusinessUtils.checkRemoteService(f1.get());
            BusinessUtils.checkRemoteService(f2.get());
            BusinessUtils.checkRemoteService(f3.get());

            //构造map用于快速查询
            Map<Long, SysUser> finderMap = f1.get().getData();
            Map<Long, AmsOwnAddress> addressMap = f2.get().getData();
            Map<Long, SysUser> resovlerMap = f3.get().getData();

            Map<Long, String> assetMap = f4.get().stream().filter(Objects::nonNull)
                    .collect(Collectors.toMap(AsmsAssetFullInfo::getAssetId, AsmsAssetFullInfo::getAssetTypeName));

            Map<Long, Integer> reportMap = f5.get().stream().filter(Objects::nonNull)
                    .collect(Collectors.toMap(AsmsFaultReportStage::getFaultAssetId, AsmsFaultReportStage::getUrgencyDegree));

            Map<Long, Integer> dispatchMap = f6.get().stream().filter(Objects::nonNull)
                    .collect(Collectors.toMap(AsmsFaultDispatchStage::getFaultAssetId, AsmsFaultDispatchStage::getIsActiveReceive));

            Map<Long, AsmsFaultResolveStage> resovleMap = f7.get().stream().filter(Objects::nonNull)
                    .collect(Collectors.toMap(AsmsFaultResolveStage::getFaultAssetId, o -> o));

            //构造用于返回给前端的数据
            for (FaultInfoView view : faultInfoViews) {
                FaultBasicInfoVo vo = new FaultBasicInfoVo();

                //故障信息
                BeanUtils.copyProperties(view, vo);

                //报修人员信息
                SysUser finder = finderMap.get(view.getFaultFindUserId());
                if (Objects.nonNull(finder)) {
                    BeanUtils.copyProperties(finder, vo);
                }

                //报修地址信息
                AmsOwnAddress address = addressMap.get(view.getAddressId());
                if (Objects.nonNull(address)) {
                    BeanUtils.copyProperties(address, vo);
                }

                //维修人员信息
                SysUser resovler = resovlerMap.get(view.getFaultResolveUserId());
                if (Objects.nonNull(resovler)) {
                    vo.setRepairName(resovler.getNickName());
                    vo.setRepairTel(resovler.getPhonenumber());
                }

                //故障资产名称
                String assetName = assetMap.get(view.getAssetId());
                vo.setAssetName(assetName != null ? assetName : "未知");

                //故障紧急程度
                Integer urgencyDegree = reportMap.get(view.getFaultAssetId());
                vo.setUrgencyDegree(urgencyDegree != null ? urgencyDegree : 1);

                //是否接单
                Integer isActiveReceive = dispatchMap.get(view.getFaultAssetId());
                vo.setIsActiveReceive(isActiveReceive != null ? isActiveReceive : 1);

                //延后处理信息
                AsmsFaultResolveStage resolveStage = resovleMap.get(view.getFaultAssetId());
                if (Objects.nonNull(resolveStage)) {
                    BeanUtils.copyProperties(resolveStage, vo);
                }
                vo.setCreateTime(view.getCreateTime());

                vos.add(vo);
            }

            //按创建时间降序
            vos.sort(Comparator.comparing(FaultBasicInfoVo::getCreateTime).reversed());
            AjaxResult result = AjaxResult.success(vos);
            result.put("tmplIds", Lists.newArrayList(WxSubcribConfig.FAULT_REPORT_NOTICE, WxSubcribConfig.FAULT_RESOLVE_NOTICE));
            return result;

        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

    @ApiOperation("小程序故障派单处理详情")
    @GetMapping("/getFaultDisPatchDetail")
    public R<List<FaultDispatchInfoVo>> getFaultDisPatchDetail(@ApiParam(name = "faultId", value = "故障Id", required = true) Long faultId) {
        List<AsmsFaultAsset> faultAssetList = faultAssetService.list(new QueryWrapper<AsmsFaultAsset>().in(AsmsFaultAsset.FAULT_ID, faultId));
        List<FaultDispatchInfoVo> vos = new ArrayList<>();
        for (AsmsFaultAsset faultAsset : faultAssetList) {
            AsmsAssetFullInfo assetFullInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>().eq(AsmsAssetFullInfo.ASSET_ID, faultAsset.getAssetId()), false);
            FaultDispatchInfoVo vo = new FaultDispatchInfoVo();
            //资产信息
            if (assetFullInfo != null) {
                BeanUtils.copyProperties(assetFullInfo, vo);
            }
            //故障信息
            BeanUtils.copyProperties(faultAsset, vo);
            //派单信息
            AsmsFaultResolveStage resolveStage = resovleService.getOne(new QueryWrapper<AsmsFaultResolveStage>()
                    .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAsset.getFaultAssetId()), false);
            if (resolveStage != null) {
                //已派单
                R<SysUser> repair  = userController.getUserByIdR(resolveStage.getFaultResolveUserId());
                if (R.FAIL == repair.getCode()) {
                    throw new ServiceException(repair.getMsg());
                }
                vo.setDispatch(true);
                vo.setRepairName(repair.getData().getNickName());
                vo.setRepairPhone(repair.getData().getPhonenumber());
                vo.setDispatchTime(resolveStage.getStartTime());
            }
            vos.add(vo);
        }
        return R.ok(vos);
    }

    @PostMapping("/uploadFaultImage")
    @ApiOperation("上传故障资产图片")
    public R<SysFile> uploadAssetImage(@RequestPart(value = "file") MultipartFile file) {
        R<SysFile> upload = fileController.upload(file, "fault/image");
        if (R.FAIL == upload.getCode()) {
            throw new ServiceException(upload.getMsg());
        }
        return upload;
    }

    @PostMapping("/dispatch")
    @ApiOperation("故障派单")
    @Transactional
    public AjaxResult dispatch(@RequestBody DispatchVo dispatchVo) {
        asmsReusingService.dispatch(dispatchVo);
        return AjaxResult.success("成功派单！");
    }

    @PreAuthorize
    @ApiOperation(value = "查询报修记录", response = MyReportFaultInfoVo.class)
    @GetMapping("/getMyReportFaultList")
    public R<List<MyReportFaultInfoVo>> getMyReportFaultList(@ApiParam(value = "0已撤销、1待维修、2待确认、3已完成", required = true)
                                                                 @RequestParam("status") Integer status) {
        List<MyReportFaultInfoVo> vos = new ArrayList<>();
        //先查询所有我报修的故障
        List<FaultInfoView> infoViews = faultInfoViewService.list(new QueryWrapper<FaultInfoView>()
                .eq(FaultInfoView.FAULT_FIND_USER_ID, SecurityUtils.getUserId()));
        if (infoViews.size() == 0) {
            return R.ok(vos);
        }
        Set<Long> faultAssetIdSet = infoViews.stream().map(FaultInfoView::getFaultAssetId).collect(Collectors.toSet());
        //查询不同状态的报修记录
        QueryWrapper<FaultInfoView> wrapper = new QueryWrapper<>();
        switch (status) {
            case 0:
                //查询所有已撤销的故障
                List<AsmsFaultReportStage> reportStages = reportService.list(new QueryWrapper<AsmsFaultReportStage>()
                        .select(AsmsFaultReportStage.FAULT_ASSET_ID).eq(AsmsFaultReportStage.IS_CANCEL, 0)
                        .in(AsmsFaultReportStage.FAULT_ASSET_ID, faultAssetIdSet)
                );
                Set<Long> faultAssetIds = reportStages.stream().map(AsmsFaultReportStage::getFaultAssetId).collect(Collectors.toSet());
                if (faultAssetIds.size() > 0)
                    wrapper.in(FaultInfoView.FAULT_ASSET_ID, faultAssetIds);
                else
                    return R.ok(vos, "无报修记录");

                break;

            case 1:
                //查询所有待维修的故障
                List<AsmsFaultReportStage> reportStages1 = reportService.list(new QueryWrapper<AsmsFaultReportStage>()
                        .select(AsmsFaultReportStage.FAULT_ASSET_ID).eq(AsmsFaultReportStage.IS_CANCEL, 1)
                        .in(AsmsFaultReportStage.FAULT_ASSET_ID, faultAssetIdSet)
                );
                Set<Long> faultAssetIds2 = reportStages1.stream().map(AsmsFaultReportStage::getFaultAssetId).collect(Collectors.toSet());
                if (faultAssetIds2.size() > 0)
                    wrapper.in(FaultInfoView.FAULT_ASSET_ID, faultAssetIds2).lt(FaultInfoView.STAGE, 4);
                else
                    return R.ok(vos, "无报修记录");

                break;

            case 2:
                //查询所有待确认的故障
                List<AsmsFaultConfirmStage> confirmStages = confirmService.list(new QueryWrapper<AsmsFaultConfirmStage>()
                        .select(AsmsFaultConfirmStage.FAULT_ASSET_ID).eq(AsmsFaultConfirmStage.STATUS, 0)
                        .in(AsmsFaultConfirmStage.FAULT_ASSET_ID, faultAssetIdSet)
                );
                Set<Long> faultAssetIds1 = confirmStages.stream().map(AsmsFaultConfirmStage::getFaultAssetId).collect(Collectors.toSet());
                if (faultAssetIds1.size() > 0)
                    wrapper.in(FaultInfoView.FAULT_ASSET_ID, faultAssetIds1).eq(FaultInfoView.STAGE, 4);
                else
                    return R.ok(vos, "无报修记录");

                break;

            case 3:
                //查询所有已完成的故障
                wrapper.eq(FaultInfoView.IS_FINISH, 0).in(FaultInfoView.FAULT_ASSET_ID, faultAssetIdSet);
                break;
        }

        List<FaultInfoView> list = faultInfoViewService.list(wrapper);
        if (list.size() == 0) return R.ok(vos, "无报修记录");

        Set<Long> addressIds = new HashSet<>();
        Set<Long> typeIds = new HashSet<>();
        Set<Long> faultAssetIds2 = new HashSet<>();
        Set<Long> assetIds = new HashSet<>();
        for (FaultInfoView faultInfoView : list) {
            addressIds.add(faultInfoView.getAddressId());
            typeIds.add(faultInfoView.getAssetTypeId());
            assetIds.add(faultInfoView.getAssetId());
            if (faultInfoView.getStage().equals(3))
                faultAssetIds2.add(faultInfoView.getFaultAssetId());
        }

        //并行执行、Map查询节约时间
        CompletableFuture<R<Map<Long, AmsAssetType>>> future1 = CompletableFuture.supplyAsync(() ->
                assetTypeController.getAddressByIds(typeIds.toArray(new Long[0]))
        );

        CompletableFuture<R<Map<Long, AmsOwnAddress>>> future2 = CompletableFuture.supplyAsync(() ->
                amsOwnAddressController.getAddressByIds(addressIds.toArray(new Long[0]))
        );

        CompletableFuture<List<AsmsFaultResolveStage>> future3 = CompletableFuture.supplyAsync(() ->
                resovleService.list(new QueryWrapper<AsmsFaultResolveStage>()
                        .in(faultAssetIds2.size() > 0, AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetIds2)
                        .ne(AsmsFaultResolveStage.STATUS, -2))
        );

        CompletableFuture<List<AsmsAssetFullInfo>> future4 = CompletableFuture.supplyAsync(() ->
                asmsAssetFullInfoService.list(new QueryWrapper<AsmsAssetFullInfo>()
                        .select(AsmsAssetFullInfo.ASSET_ID, AsmsAssetFullInfo.SN)
                        .in(AsmsAssetFullInfo.ASSET_ID, assetIds))
        );

        try {
            R<Map<Long, AmsAssetType>> rAssetTypes = future1.get();
            R<Map<Long, AmsOwnAddress>> rAmsOwnAddresses = future2.get();
            if (R.FAIL == rAssetTypes.getCode()) {
                throw new ServiceException(rAssetTypes.getMsg());
            }
            if (R.FAIL == rAmsOwnAddresses.getCode()) {
                throw new ServiceException(rAmsOwnAddresses.getMsg());
            }
            Map<Long, AsmsFaultResolveStage> resolveStageMap = future3.get().stream().collect(Collectors.toMap(AsmsFaultResolveStage::getFaultAssetId, o -> o));
            Map<Long, String> assetMap = future4.get().stream().collect(Collectors.toMap(AsmsAssetFullInfo::getAssetId, AsmsAssetFullInfo::getSn));
            for (FaultInfoView fiv : list) {
                MyReportFaultInfoVo vo = new MyReportFaultInfoVo();
                BeanUtils.copyProperties(fiv, vo);
                vo.setSn(assetMap.get(fiv.getAssetId()));

                AmsAssetType type = rAssetTypes.getData().get(fiv.getAssetTypeId());
                if (type != null) {
                    vo.setAssetName(type.getAssetTypeName());
                }
                AmsOwnAddress address = rAmsOwnAddresses.getData().get(fiv.getAddressId());
                if (address != null) {
                    vo.setAddress(address.getFullName());
                }

                //查询待维修的故障，并且该故障正在维修中
                if (status.equals(1) && fiv.getStage().equals(3)) {
                    AsmsFaultResolveStage resolveStage = resolveStageMap.get(fiv.getFaultAssetId());
                    vo.setEstimateFixTime(resolveStage.getEstimateFixTime());
                    if (resolveStage.getIsDelayResolve() != null && resolveStage.getIsDelayResolve().equals(0)) {
                        vo.setDelayDayNum(resolveStage.getDelayDayNum());
                        vo.setDelayReason(resolveStage.getDelayReason());
                    }
                }
                vos.add(vo);
            }
            vos.sort(Comparator.comparing(MyReportFaultInfoVo::getCreateTime).reversed());
            return R.ok(vos);

        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            return R.fail("系统错误！");
        }
    }

    @PreAuthorize
    @ApiOperation("获取故障的详细信息实时进度等")
    @GetMapping("/getFaultFullInfo")
    public R<FaultFullInfoVo> getFaultFullInfo(@ApiParam(value = "故障资产Id", required = true)
                                               @RequestParam("faultAssetId") Long faultAssetId) {
        return R.ok(asmsReusingService.getFaultFullInfo(faultAssetId));
    }

    @PreAuthorize
    @ApiOperation(value = "查看我的维修工单", response = GetMyRepairListVo.class)
    @GetMapping("/getMyRepairList")
    public R<List<GetMyRepairListVo>> getMyRepairList(@ApiParam(value = "0未接单、1待维修、2已维修、3已完成", required = true)
                                                          @RequestParam("status") Integer status) {
        //查询与我有关联的工单
        List<GetMyRepairListVo> resultList = new ArrayList<>();

        List<AsmsFaultResolveStage> list = resovleService.list(new QueryWrapper<AsmsFaultResolveStage>()
                .select(AsmsFaultResolveStage.FAULT_ASSET_ID)
                .eq(AsmsFaultResolveStage.FAULT_RESOLVE_USER_ID, SecurityUtils.getUserId())
                .ne(AsmsFaultResolveStage.STATUS, -2)
        );
        Set<Long> faultAssetIds = list.stream().map(AsmsFaultResolveStage::getFaultAssetId).collect(Collectors.toSet());

        if (faultAssetIds.size() == 0) return R.ok(resultList);

        //排除已撤销的故障
        QueryWrapper<FaultInfoView> wrapper = new QueryWrapper<>();
        Set<Long> hasCancelFaults = asmsReusingService.getHasCancelFaults();
        if (hasCancelFaults.size() != 0) {
            wrapper.notIn(FaultInfoView.FAULT_ASSET_ID, hasCancelFaults);
        }

        //查看不同状态的维修工单
        switch(status) {
            case 0:
                //查看未接单的工单
                List<AsmsFaultDispatchStage> dispatchStages = dispatchService.list(new QueryWrapper<AsmsFaultDispatchStage>()
                        .select(AsmsFaultDispatchStage.FAULT_ASSET_ID).eq(AsmsFaultDispatchStage.IS_ACTIVE_RECEIVE, 1)
                        .in(AsmsFaultDispatchStage.FAULT_ASSET_ID, faultAssetIds)
                );

                Set<Long> resultSet = dispatchStages.stream().map(AsmsFaultDispatchStage::getFaultAssetId).collect(Collectors.toSet());

                if (resultSet.size() > 0)
                    wrapper.in(FaultInfoView.FAULT_ASSET_ID, resultSet);
                else
                    return R.ok(resultList);

                break;
            case 1:
                //查看待维修的工单
                List<AsmsFaultDispatchStage> dispatchStages1 = dispatchService.list(new QueryWrapper<AsmsFaultDispatchStage>()
                        .select(AsmsFaultDispatchStage.FAULT_ASSET_ID).eq(AsmsFaultDispatchStage.IS_ACTIVE_RECEIVE, 0)
                        .in(AsmsFaultDispatchStage.FAULT_ASSET_ID, faultAssetIds)
                );

                Set<Long> resultSet3;
                Set<Long> collect2 = dispatchStages1.stream().map(AsmsFaultDispatchStage::getFaultAssetId).collect(Collectors.toSet());
                if (collect2.size() > 0) {
                    List<AsmsFaultResolveStage> list1 = resovleService.list(new QueryWrapper<AsmsFaultResolveStage>()
                            .select(AsmsFaultResolveStage.FAULT_ASSET_ID).in(AsmsFaultResolveStage.FAULT_ASSET_ID, collect2)
                            .eq(AsmsFaultResolveStage.STATUS, 0)
                    );
                    resultSet3 = list1.stream().map(AsmsFaultResolveStage::getFaultAssetId).collect(Collectors.toSet());
                } else {
                    return R.ok(resultList);
                }

                //所有我已经接单但还未维修完成的故障
                if (resultSet3.size() > 0)
                    wrapper.in(FaultInfoView.FAULT_ASSET_ID, resultSet3);
                else
                    return R.ok(resultList);

                break;
            case 2:
                //查看已维修的工单
                wrapper.eq(FaultInfoView.IS_FINISH, 1).eq(FaultInfoView.STAGE, 4).in(FaultInfoView.FAULT_ASSET_ID, faultAssetIds);
                break;
            case 3:
                //查看已完成的工单
                wrapper.eq(FaultInfoView.IS_FINISH, 0).in(FaultInfoView.FAULT_ASSET_ID, faultAssetIds);
                break;
        }

        //封装出一个维修工单Vo的列表
        List<FaultInfoView> views = faultInfoViewService.list(wrapper);
        if (views.size() == 0) return R.ok(resultList);

        Set<Long> addressIds = views.stream().map(FaultInfoView::getAddressId).collect(Collectors.toSet());
        Set<Long> ownDeptIds = views.stream().map(FaultInfoView::getOwnDeptId).collect(Collectors.toSet());
        Set<Long> finderIds = views.stream().map(FaultInfoView::getFaultFindUserId).collect(Collectors.toSet());
        Set<Long> assetIds = views.stream().map(FaultInfoView::getAssetId).collect(Collectors.toSet());
        Set<Long> faultAssetsIds = views.stream().map(FaultInfoView::getFaultAssetId).collect(Collectors.toSet());

        CompletableFuture<R<Map<Long, AmsOwnAddress>>> f1 = CompletableFuture.supplyAsync(() ->
                amsOwnAddressController.getAddressByIds(addressIds.toArray(new Long[0]))
        );
        CompletableFuture<R<List<SysDept>>> f2 = CompletableFuture.supplyAsync(() ->
                deptController.getDeptListByIds(Sets.newHashSet(ownDeptIds))
        );
        CompletableFuture<R<Map<Long, SysUser>>> f3 = CompletableFuture.supplyAsync(() ->
                userController.getUserListByIds(finderIds.toArray(new Long[0]))
        );
        CompletableFuture<List<AsmsAssetFullInfo>> f4 = CompletableFuture.supplyAsync(() ->
                asmsAssetFullInfoService.list(new QueryWrapper<AsmsAssetFullInfo>()
                        .select(AsmsAssetFullInfo.ASSET_ID, AsmsAssetFullInfo.ASSET_TYPE_NAME, AsmsAssetFullInfo.U_LEADER)
                        .in(AsmsAssetFullInfo.ASSET_ID, assetIds))
        );
        CompletableFuture<List<AsmsFaultReportStage>> f5 = CompletableFuture.supplyAsync(() ->
                reportService.list(new QueryWrapper<AsmsFaultReportStage>()
                        .select(AsmsFaultReportStage.FAULT_ASSET_ID, AsmsFaultReportStage.URGENCY_DEGREE)
                        .in(AsmsFaultReportStage.FAULT_ASSET_ID, faultAssetsIds))
        );
        CompletableFuture<List<AsmsFaultResolveStage>> f6 = CompletableFuture.supplyAsync(() ->
                resovleService.list(new QueryWrapper<AsmsFaultResolveStage>()
                        .select(AsmsFaultResolveStage.FAULT_ASSET_ID, AsmsFaultResolveStage.IS_DELAY_RESOLVE)
                        .ne(AsmsFaultResolveStage.STATUS, -2)
                        .in(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetsIds))
        );
        CompletableFuture<List<AsmsFaultDispatchStage>> f7 = CompletableFuture.supplyAsync(() ->
                dispatchService.list(new QueryWrapper<AsmsFaultDispatchStage>()
                        .select(AsmsFaultDispatchStage.FAULT_ASSET_ID, AsmsFaultDispatchStage.IS_DISPATCH, AsmsFaultDispatchStage.MAINTENANCE_CHARGE_USER_ID)
                        .in(AsmsFaultDispatchStage.FAULT_ASSET_ID, faultAssetsIds))
        );

        Map<Long, AmsOwnAddress> addressMap = new HashMap<>();
        Map<Long, SysDept> ownDeptMap = new HashMap<>();
        Map<Long, SysUser> finderMap = new HashMap<>();
        Map<Long, AsmsAssetFullInfo> assetMap = new HashMap<>();
        Map<Long, Integer> faultAssetMap = new HashMap<>();
        Map<Long, Integer> faultResovleMap = new HashMap<>();
        Map<Long, AsmsFaultDispatchStage> faultDispatchMap = new HashMap<>();
        Map<Long, SysUser> chargeUserMap = new HashMap<>();
        try {

            if (f1.get().getCode() == R.FAIL) throw new ServiceException(f1.get().getMsg());
            if (f2.get().getCode() == R.FAIL) throw new ServiceException(f2.get().getMsg());
            if (f3.get().getCode() == R.FAIL) throw new ServiceException(f3.get().getMsg());

            addressMap = f1.get().getData();
            ownDeptMap = f2.get().getData().stream().collect(Collectors.toMap(SysDept::getDeptId, o -> o));
            finderMap = f3.get().getData();
            f4.get().forEach(a -> assetMap.put(a.getAssetId(), a));
            f5.get().forEach(r -> faultAssetMap.put(r.getFaultAssetId(), r.getUrgencyDegree()));
            f6.get().forEach(re -> faultResovleMap.put(re.getFaultAssetId(), re.getIsDelayResolve()));
            f7.get().forEach(d -> faultDispatchMap.put(d.getFaultAssetId(), d));

            //查询转单人员
            Set<Long> collect = f7.get().stream().map(AsmsFaultDispatchStage::getMaintenanceChargeUserId).collect(Collectors.toSet());
            R<Map<Long, SysUser>> mapR = userController.getUserListByIds(collect.toArray(new Long[0]));
            if (mapR.getCode() == R.FAIL) throw new ServiceException(mapR.getMsg());
            chargeUserMap = mapR.getData();

        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        for (FaultInfoView view : views) {
            GetMyRepairListVo vo = new GetMyRepairListVo();
            vo.setFaultAssetId(view.getFaultAssetId());

            //设置故障位置
            AmsOwnAddress address = addressMap.get(view.getAddressId());
            SysDept dept = ownDeptMap.get(view.getOwnDeptId());
            String faultAddress = address != null ? address.getFullName() : "未知";
            String deptName = dept != null ? dept.getDeptFullName() : "未知";
            vo.setAddressFullName("【" + deptName + "】" + faultAddress);

            //设置报修人信息
            SysUser user = finderMap.get(view.getFaultFindUserId());
            vo.setNickName(user != null ? user.getNickName() : "未知");
            vo.setPhonenumber(user != null ? user.getPhonenumber() : "未知");

            //设置其他信息
            vo.setDescription(view.getDescription());
            vo.setCreateTime(view.getCreateTime());
            AsmsAssetFullInfo assetFullInfo = assetMap.get(view.getAssetId());
            if (Objects.nonNull(assetFullInfo)) {
                vo.setFaultAssetName(assetFullInfo.getAssetTypeName() != null ? assetFullInfo.getAssetTypeName() : "未知");
                vo.setCharger(assetFullInfo.getULeader() != null ? assetFullInfo.getULeader() : "未知");
            }
            vo.setUrgencyDegree(faultAssetMap.get(view.getFaultAssetId()));

            //设置是否延后处理
            if (view.getStage().equals(3)) {
                vo.setIsDelay(faultResovleMap.get(view.getFaultAssetId()));
            }

            //设置工单转让
            AsmsFaultDispatchStage dispatchStage = faultDispatchMap.get(view.getFaultAssetId());
            if (dispatchStage != null && dispatchStage.getIsDispatch().equals(0)) {
                SysUser sysUser = chargeUserMap.get(dispatchStage.getMaintenanceChargeUserId());
                if (sysUser != null) {
                    vo.setTransferWork("来自【" + sysUser.getNickName() + "】的转单，请及时接单");
                }
            }

            resultList.add(vo);
        }
        resultList.sort(Comparator.comparing(GetMyRepairListVo::getCreateTime).reversed());
        /*AjaxResult result = AjaxResult.success(resultList);
        result.put("tmplIds", Lists.newArrayList(WxSubcribConfig.DISPATCH_NOTICE_TO_REPAIR, WxSubcribConfig.FAULT_RESOLVE_NOTICE));*/
        return R.ok(resultList);
    }

    @PreAuthorize
    @Transactional
    @ApiOperation("处理故障")
    @PostMapping("/resolveFault")
    public AjaxResult resolveFault(@RequestBody AsmsFaultResolveFaultVo vo) {
        AsmsFaultDispatchStage dispatchStage = dispatchService.getOne(new QueryWrapper<AsmsFaultDispatchStage>()
                .eq(AsmsFaultDispatchStage.FAULT_ASSET_ID, vo.getFaultAssetId()));
        Long endTime = dispatchStage.getEndTime();
        Integer status = dispatchStage.getStatus();
        Long maintenanceChargeUserId = dispatchStage.getMaintenanceChargeUserId();

        //用户选择直接处理时修改派单阶段、处理阶段数据
        SysUser currentUser = tokenService.getLoginUser().getSysUser();
        if (endTime == null && status == 0 && maintenanceChargeUserId == null) {
            dispatchStage.setEndTime(System.currentTimeMillis());
            dispatchStage.setStatus(1);
            dispatchStage.setMaintenanceChargeUserId(SecurityUtils.getUserId());
            dispatchService.updateById(dispatchStage);

            AsmsFaultResolveStage resolveStage = new AsmsFaultResolveStage();
            resolveStage.setFaultAssetId(vo.getFaultAssetId());
            resolveStage.setStartTime(System.currentTimeMillis());
            resolveStage.setFaultResolveUserId(SecurityUtils.getUserId());
            resolveStage.setMaintenanceDeptId(SecurityUtils.getDeptId());
            resolveStage.setStatus(0);
            resovleService.save(resolveStage);

            vo.setRepairName(currentUser.getNickName());
            vo.setRepairPhone(currentUser.getPhonenumber());
        }

        //resolveStage对应记录的填充
        StringBuilder imageUrls = new StringBuilder();
        if (vo.getImages() != null) {
            List<String> images = vo.getImages();

            for (int i = 0; i < images.size(); i++) {
                imageUrls.append(images.get(i));

                if (i + 1 != images.size()) {
                    imageUrls.append(",");
                }
            }
        }
        resovleService.update(new UpdateWrapper<AsmsFaultResolveStage>()
                        .set(AsmsFaultResolveStage.ASSET_FAULT_REASON_ID, vo.getAssetFaultReasonId())
                        .set(AsmsFaultResolveStage.ASSET_FAULT_SOLUTION, vo.getAssetFaultSolution())
                        .set(AsmsFaultResolveStage.FAULT_TYPE, vo.getFaultType())
                        .set(AsmsFaultResolveStage.RESOLVE_TYPE, vo.getResolveType())
                        .set(AsmsFaultResolveStage.IMAGES, imageUrls.toString())
                        .set(AsmsFaultResolveStage.ASSET_FAULT_REASON, vo.getAssetFaultReason())
                        .set(AsmsFaultResolveStage.END_TIME, System.currentTimeMillis())
                        .set(AsmsFaultResolveStage.STATUS, 1)
                        .set(AsmsFaultResolveStage.LONGITUDE, vo.getLng())
                        .set(AsmsFaultResolveStage.LATITUDE, vo.getLat())
                        .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, vo.getFaultAssetId())
                        .eq(AsmsFaultResolveStage.STATUS, 0)
        );

        //开启故障确认阶段
        AsmsFaultConfirmStage confirmStage1 = confirmService.getOne(new QueryWrapper<AsmsFaultConfirmStage>()
                .eq(AsmsFaultConfirmStage.FAULT_ASSET_ID, vo.getFaultAssetId())
        );
        if (Objects.isNull(confirmStage1)) {
            AsmsFaultConfirmStage confirmStage = new AsmsFaultConfirmStage();
            confirmStage.setFaultAssetId(vo.getFaultAssetId());
            confirmStage.setStartTime(System.currentTimeMillis());
            confirmService.save(confirmStage);
        }

        //修改故障设备的阶段
        faultAssetService.update(new UpdateWrapper<AsmsFaultAsset>()
                .set(AsmsFaultAsset.STAGE, 4)
                .set(AsmsFaultAsset.ASSET_FAULT_TYPE_ID, vo.getAssetFaultReasonId())
                .set(AsmsFaultAsset.FAULT_RESOLVE_USER_ID, SecurityUtils.getUserId())
                .eq(AsmsFaultAsset.FAULT_ASSET_ID, vo.getFaultAssetId())
        );

        asyncService.sendResolveWxSubscribeMsg(vo);
        asyncService.sendFaultResolveMsgToReporter(vo);
        vo.setRepairName(currentUser.getNickName());
        vo.setRepairPhone(currentUser.getPhonenumber());
        asyncService.sendResloveResultToOldPlatform(vo);

        return AjaxResult.success("处理成功！");
    }

    @PreAuthorize
    @GetMapping("/getResolveStageInfo")
    @ApiOperation("获取故障处理的详细信息")
    public AjaxResult getResolveStageInfo(@ApiParam(name = "faultAssetId", value = "故障处理阶段Id", required = true) Long faultAssetId) {
        FaultInfoView infoView = faultInfoViewService.getOne(new QueryWrapper<FaultInfoView>()
                .eq(FaultInfoView.FAULT_ASSET_ID, faultAssetId), false);

        AsmsFaultResolveStage resolveStage = resovleService.getOne(new QueryWrapper<AsmsFaultResolveStage>()
                .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetId).ne(AsmsFaultResolveStage.STATUS, -2), false);

        AsmsAssetFullInfo assetFullInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                .eq(AsmsAssetFullInfo.ASSET_ID, infoView.getAssetId()), false);

        //将故障处理详细信息封装到Vo中
        GetResolveStageInfoVo infoVo = new GetResolveStageInfoVo();

        if (infoView.getFaultFindUserId() != null) {
            R<SysUser> user = userController.getUserByIdR(infoView.getFaultFindUserId());
            if (user.getCode() == R.FAIL) {
                throw new ServiceException(user.getMsg());
            }
            infoVo.setNickName(user.getData().getNickName());
            infoVo.setPhonenumber(user.getData().getPhonenumber());
        }
        if (infoView.getMaintenanceDeptId() != null) {
            R<SysDept> dept = deptController.getDeptById(infoView.getMaintenanceDeptId());
            if (dept.getCode() == R.FAIL) {
                throw new ServiceException(dept.getMsg());
            }
            infoVo.setMaintenanceDeptName(dept.getData().getDeptFullName());
        }
//        infoVo.setDescription(infoView.getDescription());
//        infoVo.setAssetTypeName(assetFullInfo.getAssetTypeName());
//        infoVo.setAssetTypeId(assetFullInfo.getAssetTypeId());
//        infoVo.setLeader(assetFullInfo.getULeader());

        BeanUtils.copyProperties(assetFullInfo, infoVo);

        BeanUtils.copyProperties(infoView, infoVo);
        if (resolveStage.getStatus() == 1) {
            String reason = "";
            try {
                reason = asmsFaultAssetReasonService
                        .getById(resolveStage.getAssetFaultReasonId())
                        .getFaultReason();
            } catch (Exception e) {

            }
            reason += resolveStage.getAssetFaultReason() != null ? "及" + resolveStage.getAssetFaultReason() : "";
            infoVo.setFaultReason(reason);
            infoVo.setAssetFaultSolution(resolveStage.getAssetFaultSolution());
            infoVo.setFaultType(resolveStage.getFaultType());
            infoVo.setResolveType(resolveStage.getResolveType());
        }
        AsmsFaultConfirmStage confirmStage = confirmService.getOne(new QueryWrapper<AsmsFaultConfirmStage>()
                .eq(AsmsFaultConfirmStage.FAULT_ASSET_ID, faultAssetId), false);
        if (confirmStage != null && confirmStage.getStatus() == 1) {
            BeanUtils.copyProperties(confirmStage, infoVo);
        }
        if (infoView.getAddressId() != null) {

            infoVo.setAddressFullName(assetFullInfo.getOwnDeptName() + assetFullInfo.getAddressFullName());
        }
        infoVo.setImages(resolveStage.getImages());
        infoVo.setReportTime(DateUtils.parseLongToStr(DateUtils.YYYY_MM_DD_HH_MM_SS_Z, infoView.getCreateTime()));
        infoVo.setResolveTime(DateUtils.parseLongToStr(DateUtils.YYYY_MM_DD_HH_MM_SS_Z, resolveStage.getEndTime()));
        return AjaxResult.success(infoVo);
    }

    @PreAuthorize
    @PostMapping("/appraise")
    @ApiOperation("用户对故障的处理做出评价")
    public AjaxResult appraise(@RequestBody AsmsFaultConfirmStageAppraiseVo vo) {
        //对处理结果做出评价
        confirmService.update(new UpdateWrapper<AsmsFaultConfirmStage>()
                .set(AsmsFaultConfirmStage.END_TIME, System.currentTimeMillis())
                .set(AsmsFaultConfirmStage.EFFICIENCY_SCORE, vo.getEfficiencyScore())
                .set(AsmsFaultConfirmStage.ATTITUDE_SCORE, vo.getAttitudeScore())
                .set(AsmsFaultConfirmStage.QUALITY_SCORE, vo.getQualityScore())
                .set(AsmsFaultConfirmStage.EVALUATION_CONTENT, vo.getEvaluationContent())
                .set(AsmsFaultConfirmStage.STATUS, 1)
                .eq(AsmsFaultConfirmStage.FAULT_ASSET_ID, vo.getFaultAssetId())
        );

        //修改该故障的状态
        faultAssetService.update(new UpdateWrapper<AsmsFaultAsset>().set(AsmsFaultAsset.IS_FINISH, 0)
                .eq(AsmsFaultAsset.FAULT_ASSET_ID, vo.getFaultAssetId())
        );

        //故障处理评价通知  对象 资产维护人本人   内容：   按模板填写
        AsmsFaultResolveStage resolveStage = resovleService.getOne(new QueryWrapper<AsmsFaultResolveStage>()
                        .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, vo.getFaultAssetId())
                        .ne(AsmsFaultResolveStage.STATUS, -2), false);
        asyncService.sendConfirmResultToWxMaSubscribe(resolveStage, vo);

        return AjaxResult.success("评价完成！");
    }

    @GetMapping("/test")
    public void test() {
        try {
            WxMaConfiguration.getMaService().getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
                    .templateId(WxSubcribConfig.FAULT_REPORT_NOTICE)
                    .data(Lists.newArrayList(
                            new WxMaSubscribeMessage.MsgData("thing2", "电脑坏了"),//故障描述
                            new WxMaSubscribeMessage.MsgData("thing3", "杨军"),//报修人姓名
                            new WxMaSubscribeMessage.MsgData("phone_number4", "17394946848"),//报修人电话
                            new WxMaSubscribeMessage.MsgData("time5", "2021年11月3日 16:42:50"),//报修时间
                            new WxMaSubscribeMessage.MsgData("thing7", "四川成都金牛振兴路13号4栋108")//报修地址
                            )
                    )
                    .toUser("oxLRa5IFBRTt3fiY0W4eiYaX2BpM")
                    .miniprogramState("developer")
                    .page("pages/index/index")
                    .build());
        } catch (WxErrorException e) {
            System.out.println("订阅消息发送失败" + e.getMessage());
        }
    }


    @GetMapping("/getCode")
    public void createQCode(@RequestParam("code") String code, HttpServletResponse response) throws WxErrorException {
        File file = WxMaConfiguration.getMaService().getQrcodeService().createWxaCodeUnlimit(code, "pages/index/index");
        ServletOutputStream out = null;
        FileInputStream ips = null;
        try {
            ips = new FileInputStream(file);
            response.setContentType("multipart/form-data");
            //为文件重新设置名字，采用数据库内存储的文件名称
            response.addHeader("Content-Disposition", "attachment; filename=\"" + code + ".jpg");
            out = response.getOutputStream();
            //读取文件流
            int len = 0;
            byte[] buffer = new byte[1024 * 10];
            while ((len = ips.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
                ips.close();
            } catch (IOException e) {
                System.out.println("关闭流出现异常");
                e.printStackTrace();
            }
        }
    }

    @PostMapping("/import")
    @Transactional
    public AjaxResult importData(MultipartFile file) {
        List<FaultImportVo> list = null;
        try {
            ExcelUtil<FaultImportVo> util = new ExcelUtil<FaultImportVo>(FaultImportVo.class);
            list = util.importExcel(file.getInputStream());
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return AjaxResult.error("解析Excel出现错误，请确定数据是否为空并是否按照要求填写！");
        }
        Set<String> openIds = new HashSet<>();

        for (FaultImportVo faultImportVo : list) {
            openIds.add(faultImportVo.getFaultFindUserOpenId());
            openIds.add(faultImportVo.getFaultResolveUserOpenId());
        }
        R<Map<String, SysUser>> userByOpenIds = userController.getUserByOpenIds(openIds);
        Map<String, SysUser> userMap = userByOpenIds.getData();
        for (FaultImportVo faultImportVo : list) {
            if (StringUtils.isEmpty(faultImportVo.getFaultFindUserOpenId()) || userMap.get(faultImportVo.getFaultFindUserOpenId()) == null) {
                continue;
            }
            AsmsFault fault = new AsmsFault();
            fault.setRemark("原系统数据同步" + faultImportVo.getRemark());
            fault.setCreateTime(faultImportVo.getReportTime());
            SysUser finderUser = userMap.get(faultImportVo.getFaultFindUserOpenId());
            fault.setFaultFindUserId(finderUser.getUserId());
            AsmsOwnAddressAssetCode assetCode = asmsOwnAddressAssetCodeService.getOne(new QueryWrapper<AsmsOwnAddressAssetCode>().eq(AsmsOwnAddressAssetCode.CODE, faultImportVo.getAddressCode()));
            if (assetCode != null) {
                fault.setAddressId(assetCode.getAddressId());
            }
            fault.setUpdateBy(finderUser.getNickName());
            fault.setCreateBy(finderUser.getNickName());
            fault.setUpdateTime(faultImportVo.getReportTime());
            faultService.save(fault);
            AsmsFaultAsset faultAsset = new AsmsFaultAsset();
            faultAsset.setFaultId(fault.getFaultId());
            faultAsset.setStage(5);
            //faultAsset.setAssetFaultTypeId();
            BeanUtils.copyProperties(faultImportVo, faultAsset);
            AsmsAssetFullInfo fullInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>().eq(AsmsAssetFullInfo.ASSET_CODE, faultImportVo.getProductCode()));
            if (fullInfo == null) continue;
            BeanUtils.copyProperties(fullInfo, faultAsset);
            faultAssetService.save(faultAsset);
            AsmsFaultReportStage reportStage = new AsmsFaultReportStage();
            reportStage.setStartTime(faultImportVo.getReportTime());
            reportStage.setEndTime(faultImportVo.getReportTime() + RandomUtils.nextInt(1, 10) * 60 * 60 * 1000);
            reportStage.setStatus(1);
            reportStage.setReason("");
            reportStage.setOwnChargeDeptId(fullInfo.getOwnDeptId());
            List<SysUser> oChargers = userController.getOwnDeptCharger(fullInfo.getOwnDeptId()).getData();
            reportStage.setOwnChargeUserId(oChargers != null && oChargers.size() > 0 ? oChargers.get(0).getUserId() : 0);
            reportStage.setFaultAssetId(faultAsset.getFaultAssetId());
            reportService.save(reportStage);
            AsmsFaultDispatchStage dispatchStage = new AsmsFaultDispatchStage();
            dispatchStage.setFaultAssetId(faultAsset.getFaultAssetId());
            List<SysUser> mChargers = userController.getMDeptCharger(fullInfo.getMaintenanceDeptId()).getData();
            dispatchStage.setMaintenanceChargeUserId(mChargers != null && mChargers.size() > 0 ? mChargers.get(0).getUserId() : 0);
            dispatchStage.setMaintenanceDeptId(fullInfo.getMaintenanceDeptId());
            dispatchStage.setStartTime(faultImportVo.getReportTime());
            if (StringUtils.isEmpty(faultImportVo.getFaultResolveUserOpenId())) {
                faultAsset.setStage(2);
                faultAsset.setIsFinish(1);
                faultAssetService.updateById(faultAsset);
                dispatchStage.setStatus(1);
                dispatchService.save(dispatchStage);
                continue;
            }
            dispatchStage.setStatus(1);
            dispatchStage.setEndTime(faultImportVo.getReportTime() + RandomUtils.nextInt(1, 10) * 60 * 60 * 1000);
            dispatchService.save(dispatchStage);
            AsmsFaultResolveStage resolveStage = new AsmsFaultResolveStage();
            resolveStage.setFaultAssetId(faultAsset.getFaultAssetId());

            SysUser resolveUser = userMap.get(faultImportVo.getFaultResolveUserOpenId());
            if (resolveUser != null) {
                resolveStage.setFaultResolveUserId(resolveUser.getUserId());
                faultAsset.setStage(3);

                faultAssetService.updateById(faultAsset);
            }
            resolveStage.setMaintenanceDeptId(fullInfo.getMaintenanceDeptId());
            resolveStage.setStartTime(faultImportVo.getReportTime());
            if (faultImportVo.getIsFinish() == 0) {
                resolveStage.setStatus(1);

                resolveStage.setEndTime(faultImportVo.getEndTime());
                resolveStage.setAssetFaultReason(faultImportVo.getAssetFaultReasonFull());
                //String assetFaultReason = faultImportVo.getAssetFaultReason();
                //resolveStage.setAssetFaultReasonId();
                faultAsset.setStage(4);
                faultAsset.setIsFinish(0);
                faultAssetService.updateById(faultAsset);
                resolveStage.setFaultType(faultImportVo.getFaultType());
                resolveStage.setResolveType(faultImportVo.getResolveType());
                resolveStage.setAssetFaultSolution(faultImportVo.getAssetFaultSolution());
            } else {
                resolveStage.setStatus(0);
            }
            resovleService.save(resolveStage);
            AsmsFaultConfirmStage confirmStage = new AsmsFaultConfirmStage();
            confirmStage.setFaultAssetId(faultAsset.getFaultAssetId());
            confirmStage.setStartTime(faultImportVo.getReportTime());
            confirmStage.setEndTime(faultImportVo.getEndTime());
            if (faultImportVo.getScore() > 0) {
                faultAsset.setStage(5);
                faultAssetService.updateById(faultAsset);
                confirmStage.setStatus(2);
                confirmStage.setAttitudeScore(RandomUtils.nextInt(3, 5));
                confirmStage.setQualityScore(RandomUtils.nextInt(3, 5));
                confirmStage.setEfficiencyScore(RandomUtils.nextInt(3, 5));
            }
            confirmStage.setStatus(1);
            confirmStage.setAttitudeScore(5);
            confirmStage.setQualityScore(5);
            confirmStage.setEfficiencyScore(5);
            confirmService.save(confirmStage);
        }
        return success();
    }

    @PreAuthorize
    @ApiOperation("重新派单")
    @PostMapping("/dispatchAgain")
    public AjaxResult dispatchAgain(@RequestBody DispatchWorkDto dto) {
        Long faultAssetId = dto.getFaultAssetId();
        Long userId = dto.getUserId();
        //修改维修人员为新的维修人员
        AsmsFaultResolveStage resolveStage = resovleService.getOne(new QueryWrapper<AsmsFaultResolveStage>()
                        .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetId).ne(AsmsFaultResolveStage.STATUS, -2), false);
        resolveStage.setFaultResolveUserId(userId);
        resovleService.updateById(resolveStage);

        AsmsFaultAsset faultAsset = faultAssetService.getById(faultAssetId);
        faultAsset.setFaultResolveUserId(userId);
        faultAssetService.updateById(faultAsset);

        //查询故障资产信息
        AsmsAssetFullInfo faultAssetInfo = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                .select(AsmsAssetFullInfo.ASSET_TYPE_NAME, AsmsAssetFullInfo.ADDRESS_FULL_NAME)
                .eq(AsmsAssetFullInfo.ASSET_ID, faultAsset.getAssetId()), false);

        //查询新的维修人员
        R<SysUser> newRepairR = userController.getUserByIdR(userId);
        BusinessUtils.checkRemoteService(newRepairR);
        SysUser newRepairUser = newRepairR.getData();

        //查询报修人员
        AsmsFault asmsFault = faultService.getOne(new QueryWrapper<AsmsFault>()
                .eq(AsmsFault.FAULT_ID, faultAsset.getFaultId()));
        R<SysUser> finderUserR = userController.getUserByIdR(asmsFault.getFaultFindUserId());
        BusinessUtils.checkRemoteService(finderUserR);
        SysUser finderUser = finderUserR.getData();

        asyncService.sendDispatchWxSubscribeMsg(newRepairUser, finderUser, faultAsset.getDescription(),
                faultAssetInfo.getAddressFullName(), faultAsset.getCreateTime(), faultAssetInfo.getAssetTypeName(),
                faultAssetId, faultAsset.getDescriptionImages(), resolveStage.getStatus());

        return AjaxResult.success("重新派单成功");
    }

    @ApiOperation("批量上传图片")
    @PostMapping("/batchUploadImages")
    public AjaxResult batchUploadImages(@RequestPart("images") List<MultipartFile> images) {
        R<List<SysFile>> listR = fileController.batchUpload(images, "fault/image");
        if (listR.getCode() == R.FAIL) return AjaxResult.error(listR.getMsg());
        List<String> urls = new ArrayList<>();
        if (listR.getData() != null) {
           urls = listR.getData().stream().map(SysFile::getUrl).collect(Collectors.toList());
        }
        return AjaxResult.success(urls);
    }

    @ApiOperation("用户确认故障未解决")
    @GetMapping("/faultUnResovle")
    public AjaxResult faultUnResovle(@RequestParam("faultAssetId") Long faultAssetId) {
        //将故障的状态修改为正在处理中
        faultAssetService.update(new UpdateWrapper<AsmsFaultAsset>()
                .set(AsmsFaultAsset.STAGE, 3).eq(AsmsFaultAsset.FAULT_ASSET_ID, faultAssetId)
        );

        //将故障原来的处理阶段信息的状态修改为未解决
        AsmsFaultResolveStage origin = resovleService.getOne(new QueryWrapper<AsmsFaultResolveStage>()
                .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetId).eq(AsmsFaultResolveStage.STATUS, 1)
        );
        origin.setStatus(-2);
        resovleService.updateById(origin);

        //新增一条故障处理阶段的数据
        AsmsFaultResolveStage resolveStage = new AsmsFaultResolveStage();
        resolveStage.setFaultAssetId(faultAssetId)
                    .setStartTime(System.currentTimeMillis())
                    .setFaultResolveUserId(origin.getFaultResolveUserId())
                    .setMaintenanceDeptId(origin.getMaintenanceDeptId())
                    .setStatus(0);
        resovleService.save(resolveStage);

        //发送微信通知
        R<SysUser> userR = userController.getUserByIdR(origin.getFaultResolveUserId());
        BusinessUtils.checkRemoteService(userR);
        if (Objects.isNull(userR.getData())) {
            return AjaxResult.success();
        }

        //获取报修人信息
        FaultInfoView view = faultInfoViewService.getOne(new QueryWrapper<FaultInfoView>()
                .select(FaultInfoView.FAULT_FIND_USER_ID, FaultInfoView.ASSET_ID)
                .eq(FaultInfoView.FAULT_ASSET_ID, faultAssetId), false);
        R<SysUser> sysUserR = userController.getUserByIdR(view.getFaultFindUserId());
        BusinessUtils.checkRemoteService(sysUserR);
        StringBuilder userInfo = new StringBuilder();
        userInfo.append(StringUtils.isNotEmpty(sysUserR.getData().getNickName()) ? sysUserR.getData().getNickName() : "未知");
        if (StringUtils.isNotEmpty(sysUserR.getData().getPhonenumber())) {
            userInfo.append("【").append(sysUserR.getData().getPhonenumber()).append("】");
        }

        //获取故障资产和故障地址
        AsmsAssetFullInfo asset = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                .eq(AsmsAssetFullInfo.ASSET_ID, view.getAssetId()), false);

        UnResovleFaultMsgBo bo = new UnResovleFaultMsgBo();
        bo.setOpenId(userR.getData().getWxOpenId());
        bo.setFinderInfo(userInfo.toString());
        bo.setFaultAssetName(asset.getAssetTypeName());
        bo.setFaultAddress(asset.getAddressFullName());
        bo.setRemark("请及时处理未解决的故障");
        asyncService.sendWxMsgWhenUnResovleFault(bo);

        return AjaxResult.success();
    }

    @ApiOperation("用户催单")
    @GetMapping("/urgeResovleFault")
    public AjaxResult urgeResovleFault(@RequestParam("faultAssetId") Long faultAssetId) {
        AsmsFaultAsset faultAsset = faultAssetService.getOne(new QueryWrapper<AsmsFaultAsset>()
                .select(AsmsFaultAsset.STAGE, AsmsFaultAsset.FAULT_RESOLVE_USER_ID, AsmsFaultAsset.CREATE_TIME,
                        AsmsFaultAsset.ASSET_ID, AsmsFaultAsset.URGU_WORK_TIME, AsmsFaultAsset.MAINTENANCE_DEPT_ID)
                .eq(AsmsFaultAsset.FAULT_ASSET_ID, faultAssetId)
        );

        //若24小时内催过单了，则不能催单
        long judgeTime = 1000L * 60 * 60 * 24;
        if (faultAsset.getUrguWorkTime() != null &&
                (System.currentTimeMillis() - faultAsset.getUrguWorkTime()) < judgeTime) {
            return AjaxResult.error("你已经催单了哦");
        }

        Long userId;
        String remark;
        if (faultAsset.getStage().equals(2)) {
            //若当前故障还未派单，则发送微信通知给维护方管理员
            R<List<SysUser>> listR = userController.getMDeptCharger(faultAsset.getMaintenanceDeptId());
            BusinessUtils.checkRemoteService(listR);
            if (Objects.nonNull(listR.getData())) {
                userId = listR.getData().get(0).getUserId();
            }
            remark = "请及时派单";
        } else {
            //若当前故障已派单，则发送微信通知给技术人员
            userId = faultAsset.getFaultResolveUserId();
            remark = "请及时处理故障";
        }
        userId = SecurityUtils.getUserId();
        R<SysUser> userR = userController.getUserByIdR(userId);
        BusinessUtils.checkRemoteService(userR);
        if (Objects.isNull(userR.getData())) {
            return AjaxResult.success();
        }

        //发送微信通知
        AsmsAssetFullInfo asset = asmsAssetFullInfoService.getOne(new QueryWrapper<AsmsAssetFullInfo>()
                .select(AsmsAssetFullInfo.ASSET_TYPE_NAME, AsmsAssetFullInfo.OWN_DEPT_NAME)
                .eq(AsmsAssetFullInfo.ASSET_ID, faultAsset.getAssetId())
        );
        UrgeWorkBo bo = new UrgeWorkBo();
        bo.setOpenId(userR.getData().getWxOpenId());
        bo.setRemark(remark);
        bo.setTime(faultAsset.getCreateTime());
        bo.setContent("【" + asset.getAssetTypeName() + "】发生故障");
        bo.setAddress(asset.getOwnDeptName());
        asyncService.sendWxMsgWhenUserUrgeWork(bo);

        //更新催单时间
        faultAssetService.update(new UpdateWrapper<AsmsFaultAsset>()
                .set(AsmsFaultAsset.URGU_WORK_TIME, System.currentTimeMillis())
                .eq(AsmsFaultAsset.FAULT_ASSET_ID, faultAssetId)
        );

        return AjaxResult.success();
    }

    public void updateFaultAsset(Long userId, Long faultAssetId) {
        faultAssetService.update(new UpdateWrapper<AsmsFaultAsset>()
                .set(AsmsFaultAsset.FAULT_RESOLVE_USER_ID, userId)
                .eq(AsmsFaultAsset.FAULT_ASSET_ID, faultAssetId)
        );
    }

    public void updateResovleStage(Long userId, Long faultAssetId) {
        resovleService.update(new UpdateWrapper<AsmsFaultResolveStage>()
                .set(AsmsFaultResolveStage.FAULT_RESOLVE_USER_ID, userId)
                .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, faultAssetId)
                .ne(AsmsFaultResolveStage.STATUS, -2)
        );
    }

    @ApiOperation("技术人员接单")
    @PostMapping("/receiveWork")
    public AjaxResult receiveWork(@RequestBody WorkOrderDto dto) {
        //判断预计维修时间是否有效
        if (dto.getEstimateFixTime() < System.currentTimeMillis()) {
            return AjaxResult.error("预计维修时间无效");
        }
        dispatchService.update(new UpdateWrapper<AsmsFaultDispatchStage>()
                .set(AsmsFaultDispatchStage.IS_ACTIVE_RECEIVE, 0)
                .eq(AsmsFaultDispatchStage.FAULT_ASSET_ID, dto.getFaultAssetId())
        );
        resovleService.update(new UpdateWrapper<AsmsFaultResolveStage>()
                .set(AsmsFaultResolveStage.ESTIMATE_FIX_TIME, dto.getEstimateFixTime())
                .set(AsmsFaultResolveStage.STATUS, 0)
                .eq(AsmsFaultResolveStage.FAULT_ASSET_ID, dto.getFaultAssetId())
        );
        //如果我接的是自己转出去的工单，则修改故障维修人员
        AsmsFaultDispatchStage dispatchStage = dispatchService.getOne(new QueryWrapper<AsmsFaultDispatchStage>()
                .select(AsmsFaultDispatchStage.MAINTENANCE_CHARGE_USER_ID).eq(AsmsFaultDispatchStage.FAULT_ASSET_ID, dto.getFaultAssetId()), false);
        if (dispatchStage != null && dispatchStage.getMaintenanceChargeUserId() != null &&
                dispatchStage.getMaintenanceChargeUserId().equals(SecurityUtils.getUserId())) {
            //修改故障资产信息中的维修人员
            updateFaultAsset(SecurityUtils.getUserId(), dto.getFaultAssetId());
            //修改故障处理阶段的维修人员
            updateResovleStage(SecurityUtils.getUserId(), dto.getFaultAssetId());
        }
        return AjaxResult.success();
    }

    @ApiOperation("技术人员转单")
    @PostMapping("/dispatchWork")
    public AjaxResult dispatchWork(@RequestBody DispatchWorkDto dto) {
        if (dto.getUserId().equals(SecurityUtils.getUserId())) {
            return AjaxResult.error("不能转单给自己！");
        }
        //设置派单人员为当前用户并调整转单状态为是
        dispatchService.update(new UpdateWrapper<AsmsFaultDispatchStage>()
                .set(AsmsFaultDispatchStage.MAINTENANCE_CHARGE_USER_ID, SecurityUtils.getUserId())
                .set(AsmsFaultDispatchStage.IS_DISPATCH, 0)
                .eq(AsmsFaultDispatchStage.FAULT_ASSET_ID, dto.getFaultAssetId())
        );
        //修改维修人员
        updateFaultAsset(dto.getUserId(), dto.getFaultAssetId());
        updateResovleStage(dto.getUserId(), dto.getFaultAssetId());

        return AjaxResult.success();
    }

}
